package com.example.business.client;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.loadbalancer.*;
import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import reactor.core.publisher.Mono;

import java.util.List;
import java.util.Random;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 自定义负载均衡策略
 * @author zhangl
 */
@Slf4j
public class GrayVersionLoadBalancerClient implements ReactorServiceInstanceLoadBalancer {
    private ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider;
    private String serviceId;
    private final AtomicInteger position;

    public GrayVersionLoadBalancerClient(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId) {
        this(serviceInstanceListSupplierProvider, serviceId, new Random().nextInt(1000));
    }

    public GrayVersionLoadBalancerClient(ObjectProvider<ServiceInstanceListSupplier> serviceInstanceListSupplierProvider, String serviceId, int seedPosition) {
        this.serviceId = serviceId;
        this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider;
        this.position = new AtomicInteger(seedPosition);
    }

    @Override
    public Mono<Response<ServiceInstance>> choose(Request request) {
        RequestDataContext responseData = (RequestDataContext) request.getContext();
        ServiceInstanceListSupplier supplier = this.serviceInstanceListSupplierProvider.getIfAvailable(NoopServiceInstanceListSupplier::new);
        //获取version
        String version =  responseData.getClientRequest().getHeaders().getFirst("version");
        log.info("GrayVersionLoadBalancerClient#choose version :{}", version);
        return supplier.get(request).next().map(list -> processInstanceResponse(list, version));
    }

    private Response<ServiceInstance> processInstanceResponse(List<ServiceInstance> instances, String version) {
        // 注册中心无可用实例
        if (instances.isEmpty()) {
            return new EmptyResponse();
        }

        if (!StringUtils.isEmpty(version)) {
            // 遍历可以实例元数据，若匹配则返回此实例
            List<ServiceInstance> serviceInstances = instances.stream()
                    .filter(instance -> version.equalsIgnoreCase(instance.getMetadata().get("version")))
                    .collect(Collectors.toList());

            if (!serviceInstances.isEmpty()) {
                log.info("存在灰度实例 [{}] version : {}",this.serviceId,version);
                return processRibbonInstanceResponse(serviceInstances);
            }
        }

        return processRibbonInstanceResponse(instances);

    }


    /**
     * 自定义负载均衡器
     * @param instances
     * @return
     */
    private Response<ServiceInstance> processRibbonInstanceResponse(List<ServiceInstance> instances) {
        int pos = Math.abs(this.position.incrementAndGet());
        ServiceInstance instance = instances.get(pos % instances.size());
        return new DefaultResponse(instance);
    }
}
